﻿using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Internal.KuiHuaBaoDian.Services.UI;
using KuiHuaBaoDian.Services.UGUI;
using UnityEngine;

namespace KuiHuaBaoDian.Services.UGUI {

    public interface IUIView {

        IUI UI { get; }
    }

    [DisallowMultipleComponent]
    public abstract class KHBD_UIView : KHBD_MonoBehaviour, IUIView, IUIViewInternal {

        protected KHBD_UIView() : base() { }

        protected RectTransform rectTransform;

        protected IUI UI { get; private set; }

        IUI IUIView.UI => UI;

        void IUIViewInternal.SetUI(IUI value) => UI = value;

        private bool m_IsStarted;

        protected abstract void OnViewAwake();

        protected sealed override void Awake() {
            base.Awake();
            rectTransform = GetComponent<RectTransform>();
            OnViewAwake();
        }

        protected abstract void OnViewUpdate();

        private void Update() {
#if UNITY_EDITOR
            var context = KHBD.Runtime as IContext;
            if (context.IsApplicationQuit) {
                return;
            }
#endif
            if (!m_IsStarted) {
                m_IsStarted = true;
                OnEnable();
                Start();
            }
            OnViewUpdate();
            if (UI is IUIExtend extend) {
                extend.OnViewUpdate();
            } else if (KHBD.Context.IsApplicationPlaying) {
                throw new System.InvalidCastException(GetType().FullName);
            }
        }

        protected abstract void OnViewStart();

        private void Start() {
#if UNITY_EDITOR
            var context = KHBD.Runtime as IContext;
            if (context.IsApplicationQuit) {
                return;
            }
#endif
            if (m_IsStarted) {
                FixSorting();
                OnViewStart();
                if (UI is IUIExtend extend) {
                    extend.OnViewStart();
                } else if (KHBD.Context.IsApplicationPlaying) {
                    throw new System.InvalidCastException(GetType().FullName);
                }
            }
        }

        protected abstract void OnViewEnable();

        private void OnEnable() {
#if UNITY_EDITOR
            var context = KHBD.Runtime as IContext;
            if (context.IsApplicationQuit) {
                return;
            }
#endif
            if (m_IsStarted) {
                OnViewEnable();
                if (UI is IUIExtend extend) {
                    extend.OnViewEnable();
                } else if (KHBD.Context.IsApplicationPlaying) {
                    throw new System.InvalidCastException(GetType().FullName);
                }
            }
        }

        protected abstract void OnViewDisable();

        private void OnDisable() {
#if UNITY_EDITOR
            var context = KHBD.Runtime as IContext;
            if (context.IsApplicationQuit) {
                return;
            }
#endif
            if (m_IsStarted) {
                OnViewDisable();
                if (UI is IUIExtend extend) {
                    extend.OnViewDisable();
                } else if (KHBD.Context.IsApplicationPlaying) {
                    throw new System.InvalidCastException(GetType().FullName);
                }
            }
        }

        protected abstract void OnViewDestroy();

        protected sealed override void Dispose() {
            rectTransform = null;
#if UNITY_EDITOR
            var context = KHBD.Runtime as IContext;
            if (context.IsApplicationQuit) {
                return;
            }
#endif
            OnViewDestroy();
            if (UI is IUIExtend extend) {
                extend.OnViewDestroy();
            } else if (KHBD.Context.IsApplicationPlaying) {
                throw new System.InvalidCastException(GetType().FullName);
            }

            UI = null;
            m_SortingParticleSystemRendererList = null;
            m_SortingSpriteRendererList = null;
            m_SortingCanvasList = null;
            m_IsStarted = false;

            base.Dispose();
        }

        private List<ParticleSystemRenderer> m_SortingParticleSystemRendererList = new();
        private List<SpriteRenderer> m_SortingSpriteRendererList = new();
        private List<Canvas> m_SortingCanvasList = new();
        void IUIViewInternal.FixSorting() => FixSorting();
        void IUIViewInternal.FixSorting(GameObject gameObject) => FixSorting(gameObject);
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected void FixSorting() => FixSorting(gameObject);
        protected void FixSorting(GameObject gameObject) {
            UnityEngine.Assertions.Assert.IsNotNull(gameObject);

            m_SortingParticleSystemRendererList.Clear();
            gameObject.GetComponentsInChildren(true, m_SortingParticleSystemRendererList);
            var overrideSortingType = KHBD.TypeMap.Fetch<IUIViewOverrideSorting>();
            foreach (var renderer in m_SortingParticleSystemRendererList) {
                short offset = 1;
                if (renderer.TryGetComponent(overrideSortingType, out var os)) {
                    var overrideSorting = os as IUIViewOverrideSorting;
                    if (overrideSorting.Layer > -1) {
                        renderer.sortingLayerID = SortingLayer.layers[overrideSorting.Layer].id;
                    } else {
                        renderer.sortingLayerID = UI.SortingLayer;
                    }
                    offset = overrideSorting.OrderOffset;
                } else {
                    renderer.sortingLayerID = UI.SortingLayer;
                }
                renderer.sortingOrder = UI.SortingOrder + offset;
                renderer.gameObject.layer = this.gameObject.layer;
            }
            m_SortingSpriteRendererList.Clear();
            gameObject.GetComponentsInChildren(true, m_SortingSpriteRendererList);
            foreach (var renderer in m_SortingSpriteRendererList) {
                short offset = 1;
                if (renderer.TryGetComponent(overrideSortingType, out var os)) {
                    var overrideSorting = os as IUIViewOverrideSorting;
                    if (overrideSorting.Layer > -1) {
                        renderer.sortingLayerID = SortingLayer.layers[overrideSorting.Layer].id;
                    } else {
                        renderer.sortingLayerID = UI.SortingLayer;
                    }
                    offset = overrideSorting.OrderOffset;
                } else {
                    renderer.sortingLayerID = UI.SortingLayer;
                }
                renderer.sortingOrder = UI.SortingOrder + offset;
                renderer.gameObject.layer = this.gameObject.layer;
            }
            m_SortingCanvasList.Clear();
            gameObject.GetComponentsInChildren(true, m_SortingCanvasList);
            for (var i = gameObject == this.gameObject ? 1 : 0; i < m_SortingCanvasList.Count; ++i) { // 忽略第一个自身的Canvas
                var canvas = m_SortingCanvasList[i];
                short offset = 1;
                if (canvas.TryGetComponent(overrideSortingType, out var os)) {
                    var overrideSorting = os as IUIViewOverrideSorting;
                    if (overrideSorting.Layer > -1) {
                        canvas.sortingLayerID = SortingLayer.layers[overrideSorting.Layer].id;
                    } else {
                        canvas.sortingLayerID = UI.SortingLayer;
                    }
                    offset = overrideSorting.OrderOffset;
                } else {
                    canvas.sortingLayerID = UI.SortingLayer;
                }
                canvas.sortingOrder = UI.SortingOrder + offset;
                canvas.overrideSorting = true;
                canvas.gameObject.layer = this.gameObject.layer;
            }
        }
    }
}

namespace Internal.KuiHuaBaoDian.Services.UI {

    public interface IUIViewInternal {

        void SetUI(IUI value);

        void FixSorting();

        void FixSorting(GameObject gameObject);
    }
}